home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procEnviron.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  25KB  |  973 lines

  1. /* 
  2.  * procEnviron.c --
  3.  *
  4.  *    Routines to manage a process's environment.  The routines in
  5.  *    this file manage a monitor for the environments.
  6.  *
  7.  * Copyright 1986, 1988 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procEnviron.c,v 9.2 90/09/12 13:58:02 jhh Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <sprite.h>
  22. #include <proc.h>
  23. #include <procInt.h>
  24. #include <sync.h>
  25. #include <sched.h>
  26. #include <sys.h>
  27. #include <stdlib.h>
  28. #include <status.h>
  29. #include <vm.h>
  30. #include <bstring.h>
  31. #include <string.h>
  32. #include <stdio.h>
  33.  
  34. /*
  35.  * The minimum size of the environment that is allocated.  This size
  36.  * represents the number of environment variables.
  37.  */
  38.  
  39. #define    MIN_ENVIRON_SIZE    5
  40.  
  41. /*
  42.  * Structure to describe an internal version of an environment variable.
  43.  */
  44.  
  45. typedef struct ProcEnvironVar {
  46.     char    *name;
  47.     int        nameLength;
  48.     char    *value;
  49.     int        valueLength;
  50. } ProcEnvironVar;
  51.  
  52. /*
  53.  * Monitor declarations.
  54.  */
  55.  
  56. static    Sync_Lock environMonitorLock = 
  57.     Sync_LockInitStatic("Proc:environMonitorLock");
  58. #define    LOCKPTR   &environMonitorLock
  59.  
  60. static    void    DoCopyEnviron _ARGS_((int srcSize, 
  61.             ProcEnvironVar *srcVarPtr, int destSize, 
  62.             ProcEnvironVar *destVarPtr));
  63. static    void    FreeEnviron _ARGS_((register Proc_EnvironInfo *environPtr,
  64.             int size, Boolean freeEnvironInfo));
  65. static    ProcEnvironVar *FindVar _ARGS_((Proc_EnvironInfo *environPtr,
  66.             char *name));
  67. static     ProcEnvironVar *InitializeVar _ARGS_((Proc_EnvironInfo 
  68.             *environPtr, char *name, int nameLength));
  69. static    void    DecEnvironRefCount _ARGS_((Proc_EnvironInfo *environPtr));
  70.  
  71. /*
  72.  * ----------------------------------------------------------------------------
  73.  *
  74.  * Proc_InitMainEnviron --
  75.  *
  76.  *    Allocate an environment for the main process.  This sets things up
  77.  *    so that we don't have to worry about NIL environments.
  78.  *
  79.  * Results:
  80.  *    None.
  81.  *
  82.  * Side effects:
  83.  *    Environment allocated for main process.
  84.  *
  85.  * ----------------------------------------------------------------------------
  86.  */
  87.  
  88. ENTRY void
  89. ProcInitMainEnviron(procPtr)
  90.     register    Proc_ControlBlock    *procPtr;    /* Pointer to main's
  91.                              * PCB. */
  92. {
  93.     int        i;
  94.  
  95.     LOCK_MONITOR;
  96.  
  97.     procPtr->environPtr =
  98.         (Proc_EnvironInfo *) malloc(sizeof(Proc_EnvironInfo));
  99.     procPtr->environPtr->refCount = 1;
  100.     procPtr->environPtr->size = MIN_ENVIRON_SIZE;
  101.     procPtr->environPtr->varArray = (ProcEnvironVar *) 
  102.         malloc(sizeof(ProcEnvironVar) * MIN_ENVIRON_SIZE);
  103.     for (i = 0; i < MIN_ENVIRON_SIZE; i++) {
  104.     procPtr->environPtr->varArray[i].name = (char *) NIL;
  105.     procPtr->environPtr->varArray[i].value = (char *) NIL;
  106.     }
  107.  
  108.     UNLOCK_MONITOR;
  109. }
  110.  
  111.  
  112. /*
  113.  * ----------------------------------------------------------------------------
  114.  *
  115.  * Proc_SetupEnviron --
  116.  *
  117.  *    Give this process a pointer to the parents environment and increment
  118.  *    the reference count.
  119.  *
  120.  * Results:
  121.  *    None.
  122.  *
  123.  * Side effects:
  124.  *    environPtr field of process is set and reference count incremented
  125.  *    in the environment.
  126.  *
  127.  * ----------------------------------------------------------------------------
  128.  */
  129.  
  130. ENTRY void
  131. ProcSetupEnviron(procPtr)
  132.     register    Proc_ControlBlock    *procPtr;    /* Process to setup
  133.                              * environment for. */
  134. {
  135.     Proc_ControlBlock    *parentProc;
  136.  
  137.     LOCK_MONITOR;
  138.  
  139.     parentProc = Proc_GetPCB(procPtr->parentID);
  140.     procPtr->environPtr = parentProc->environPtr;
  141.     procPtr->environPtr->refCount++;
  142.  
  143.     UNLOCK_MONITOR;
  144. }
  145.  
  146.  
  147. /*
  148.  * ----------------------------------------------------------------------------
  149.  *
  150.  * DoCopyEnviron --
  151.  *
  152.  *    Copy the source environment into the destination.  It is assumed that
  153.  *    the destination is at least as big as the source.  Any remaining
  154.  *    variables in the destination environment are set to NIL.
  155.  *
  156.  * Results:
  157.  *    None.
  158.  *
  159.  * Side effects:
  160.  *    Destination gets copy of source environment with any left over
  161.  *    entries in the destination set to NIL.
  162.  *
  163.  * ----------------------------------------------------------------------------
  164.  */
  165.  
  166. INTERNAL static void
  167. DoCopyEnviron(srcSize, srcVarPtr, destSize, destVarPtr)
  168.     int                    srcSize;    /* # of variables in
  169.                              * source environ. */
  170.     register    ProcEnvironVar    *srcVarPtr;    /* Pointer to source
  171.                              * environ variables.*/
  172.     int                    destSize;    /* # of variables in
  173.                              * dest environment. */
  174.     register    ProcEnvironVar    *destVarPtr;    /* Pointer to dest
  175.                              * environ variables. */
  176. {
  177.     int        i;
  178.  
  179.     for (i = 0; i < srcSize; srcVarPtr++, destVarPtr++, i++) {
  180.     if (srcVarPtr->name != (char *) NIL) {
  181.         destVarPtr->name = (char *) malloc(srcVarPtr->nameLength + 1);
  182.         destVarPtr->nameLength = srcVarPtr->nameLength;
  183.         destVarPtr->value = (char *) malloc(srcVarPtr->valueLength + 1);
  184.         destVarPtr->valueLength = srcVarPtr->valueLength;
  185.         bcopy((Address) srcVarPtr->name, (Address) destVarPtr->name,
  186.                 srcVarPtr->nameLength + 1);
  187.         bcopy((Address) srcVarPtr->value, (Address) destVarPtr->value,
  188.                 srcVarPtr->valueLength + 1);
  189.     } else {
  190.         destVarPtr->name = (char *) NIL;
  191.         destVarPtr->value = (char *) NIL;
  192.     }
  193.     }
  194.  
  195.     for (; i < destSize; i++, destVarPtr++) {
  196.     destVarPtr->name = (char *) NIL;
  197.     destVarPtr->value = (char *) NIL;
  198.     }
  199. }
  200.  
  201.  
  202. /*
  203.  * ----------------------------------------------------------------------------
  204.  *
  205.  * FreeEnviron --
  206.  *
  207.  *    Free up all allocated memory in the environment.  The environment
  208.  *    structure itself is not freed up unless the free flag is set.
  209.  *    The actual number of variables in the environment to free up is given.
  210.  *    This allows the caller to free up an environment that has not 
  211.  *    been totally initialized.
  212.  *
  213.  * Results:
  214.  *    None.
  215.  *
  216.  * Side effects:
  217.  *    All memory allocated for the given environment is freed.
  218.  *
  219.  * ----------------------------------------------------------------------------
  220.  */
  221.  
  222. INTERNAL static void
  223. FreeEnviron(environPtr, size, freeEnvironInfo)
  224.     register    Proc_EnvironInfo    *environPtr;    /* Environment 
  225.                              * to free. */
  226.     int                    size;        /* Number of variables
  227.                                 * in the environ. */
  228.     Boolean                freeEnvironInfo;/* TRUE if should free
  229.                              * environ struct .*/
  230. {
  231.     int                    i;
  232.     register    ProcEnvironVar    *varPtr;
  233.  
  234.     for (i = 0, varPtr = environPtr->varArray; i < size; varPtr++, i++) {
  235.     if (varPtr->name != (char *) NIL) {
  236.         free((Address) varPtr->name);
  237.         free((Address) varPtr->value);
  238.     }
  239.     }
  240.     free((Address) environPtr->varArray);
  241.  
  242.     if (freeEnvironInfo) {
  243.     free((Address) environPtr);
  244.     }
  245. }
  246.  
  247.  
  248. /*
  249.  * ----------------------------------------------------------------------------
  250.  *
  251.  * FindVar --
  252.  *
  253.  *    Search the given environment for a variable with the given name.
  254.  *    This assumes that the given name is null terminated.
  255.  *
  256.  * Results:
  257.  *    A pointer to the environment variable if found, NULL otherwise.
  258.  *
  259.  * Side effects:
  260.  *    None.
  261.  *
  262.  * ----------------------------------------------------------------------------
  263.  */
  264.  
  265. INTERNAL static ProcEnvironVar *
  266. FindVar(environPtr, name)
  267.     Proc_EnvironInfo    *environPtr;    /* Environment to search. */
  268.     char        *name;        /* Name to search for. */
  269. {
  270.     register    ProcEnvironVar    *varPtr;
  271.     int                    i;
  272.  
  273.     for (i = 0, varPtr = environPtr->varArray; 
  274.      i < environPtr->size; 
  275.      varPtr++, i++) {
  276.     if (varPtr->name != (char *) NIL && 
  277.         strcmp(varPtr->name, name) == 0) {
  278.         return(varPtr);
  279.     }
  280.     }
  281.  
  282.     return((ProcEnvironVar *) NIL);
  283. }
  284.  
  285.  
  286. /*
  287.  * ----------------------------------------------------------------------------
  288.  *
  289.  * InitializeVar --
  290.  *
  291.  *    Put the given name for the environment variable into the given 
  292.  *    environment.  The environment will be expanded if necessary.
  293.  *
  294.  * Results:
  295.  *    A pointer to the initialized environment variable.
  296.  *
  297.  * Side effects:
  298.  *    Environment may be expanded.
  299.  *
  300.  * ----------------------------------------------------------------------------
  301.  */
  302.  
  303. INTERNAL static ProcEnvironVar *
  304. InitializeVar(environPtr, name, nameLength)
  305.     register Proc_EnvironInfo *environPtr;    /* Environment to put
  306.                                 * the variable in. */
  307.     char              *name;            /* Name of variable. */
  308.     int                  nameLength;       /* Length of null terminated 
  309.                          * name not including null 
  310.                          * character. */
  311. {
  312.     register    ProcEnvironVar    *varPtr;
  313.     int                    i;
  314.     int                    newSize;
  315.  
  316.     for (i = 0, varPtr = environPtr->varArray; 
  317.      i < environPtr->size; 
  318.      varPtr++, i++) {
  319.     if (varPtr->name == (char *) NIL) {
  320.         break;
  321.     }
  322.     }
  323.  
  324.     /*
  325.      * If there was no empty space in the environment then
  326.      * make the environment twice as big and set varPtr to point to
  327.      * the first null entry in the environment.
  328.      */
  329.  
  330.     if (i == environPtr->size) {
  331.     if (environPtr->size == PROC_MAX_ENVIRON_SIZE) {
  332.         return((ProcEnvironVar *) NIL);
  333.     }
  334.     newSize = environPtr->size * 2;
  335.     if (newSize > PROC_MAX_ENVIRON_SIZE) {
  336.         newSize = PROC_MAX_ENVIRON_SIZE;
  337.     }
  338.     varPtr = (ProcEnvironVar *) 
  339.             malloc(sizeof(ProcEnvironVar) * newSize);
  340.     DoCopyEnviron(environPtr->size, environPtr->varArray, 
  341.               newSize, varPtr);
  342.     FreeEnviron(environPtr, environPtr->size, FALSE);
  343.     environPtr->varArray = varPtr;
  344.     varPtr += environPtr->size;
  345.     environPtr->size = newSize;
  346.     }
  347.  
  348.     /*
  349.      * Store the name in the environment variable.
  350.      */
  351.  
  352.     varPtr->name = (char *) malloc(nameLength + 1);
  353.     varPtr->nameLength = nameLength;
  354.     bcopy((Address) name, (Address) varPtr->name, nameLength + 1);
  355.  
  356.     return(varPtr);
  357. }
  358.  
  359.  
  360. /*
  361.  * ----------------------------------------------------------------------------
  362.  *
  363.  * DecEnvironRefCount --
  364.  *
  365.  *    Decrement the reference count on the given environment.
  366.  *
  367.  * Results:
  368.  *    None.
  369.  *
  370.  * Side effects:
  371.  *    Reference count decremented for the environment.
  372.  *
  373.  * ----------------------------------------------------------------------------
  374.  */
  375.  
  376. static INTERNAL void
  377. DecEnvironRefCount(environPtr)
  378.     register    Proc_EnvironInfo    *environPtr;
  379. {
  380.     environPtr->refCount--;
  381.     if (environPtr->refCount == 0) {
  382.     FreeEnviron(environPtr, environPtr->size, TRUE);
  383.     }
  384. }
  385.  
  386.  
  387. /*
  388.  * ----------------------------------------------------------------------------
  389.  *
  390.  * ProcDecEnvironRefCount --
  391.  *
  392.  *    Decrement the reference count on the given environment.
  393.  *
  394.  * Results:
  395.  *    None.
  396.  *
  397.  * Side effects:
  398.  *    Reference count decremented for the environment.
  399.  *
  400.  * ----------------------------------------------------------------------------
  401.  */
  402.  
  403. ENTRY void
  404. ProcDecEnvironRefCount(environPtr)
  405.     register    Proc_EnvironInfo    *environPtr;
  406. {
  407.     LOCK_MONITOR;
  408.  
  409.     DecEnvironRefCount(environPtr);
  410.  
  411.     UNLOCK_MONITOR;
  412. }
  413.  
  414.  
  415. /*
  416.  * ----------------------------------------------------------------------------
  417.  *
  418.  * Proc_SetEnvironStub --
  419.  *
  420.  *    Add the given environment variable to the current process's 
  421.  *    environment.
  422.  *
  423.  * Results:
  424.  *    Return SYS_ARG_NOACCESS if the name or value are inaccessible.
  425.  *
  426.  * Side effects:
  427.  *    The enviroment of the current process is modified.
  428.  *
  429.  * ----------------------------------------------------------------------------
  430.  */
  431.  
  432. ENTRY ReturnStatus
  433. Proc_SetEnvironStub(environVar)
  434.     Proc_EnvironVar    environVar;    /* Variable to add to environment. */
  435. {
  436.     register    ProcEnvironVar    *varPtr;
  437.     register    Proc_ControlBlock    *procPtr;
  438.     char                *namePtr;
  439.     char                *valuePtr;
  440.     int                    nameLength;
  441.     int                    valueLength;
  442.     int                    nameAccLength;
  443.     int                    valueAccLength;
  444.     ReturnStatus            status;
  445.  
  446.     LOCK_MONITOR;
  447.  
  448.     procPtr = Proc_GetEffectiveProc();
  449.  
  450.     /*
  451.      * Make variable name accessible.
  452.      */
  453.  
  454.     namePtr = environVar.name;
  455.     status = Proc_MakeStringAccessible(PROC_MAX_ENVIRON_NAME_LENGTH,
  456.                        &namePtr, &nameAccLength, &nameLength);
  457.     if (status != SUCCESS) {
  458.     UNLOCK_MONITOR;
  459.     return(status);
  460.     }
  461.  
  462.     /*
  463.      * Make variable value accessible.
  464.      */
  465.  
  466.     valuePtr = environVar.value;
  467.     status = Proc_MakeStringAccessible(PROC_MAX_ENVIRON_VALUE_LENGTH,
  468.                        &valuePtr, &valueAccLength, 
  469.                        &valueLength);
  470.     if (status != SUCCESS) {
  471.     Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  472.     UNLOCK_MONITOR;
  473.     return(status);
  474.     }
  475.  
  476.     /*
  477.      * See if the variable already exists.  If not then put it in the
  478.      * environment.
  479.      */
  480.  
  481.     varPtr = FindVar(procPtr->environPtr, namePtr);
  482.     if (varPtr == (ProcEnvironVar *) NIL) {
  483.     varPtr = InitializeVar(procPtr->environPtr, namePtr, nameLength);
  484.     if (varPtr == (ProcEnvironVar *) NIL) {
  485.         Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  486.         Proc_MakeUnaccessible((Address) valuePtr, valueAccLength);
  487.         UNLOCK_MONITOR;
  488.         return(PROC_ENVIRON_FULL);
  489.     }
  490.     }
  491.     Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  492.  
  493.     /*
  494.      * Put the value of the variable into the environment.
  495.      */
  496.  
  497.     varPtr->value = (char *) malloc(valueLength + 1);
  498.     varPtr->valueLength = valueLength;
  499.     bcopy((Address) valuePtr, (Address) varPtr->value, valueLength + 1);
  500.  
  501.     Proc_MakeUnaccessible((Address) valuePtr, valueAccLength);
  502.  
  503.     UNLOCK_MONITOR;
  504.     return(SUCCESS);
  505. }
  506.  
  507.  
  508. /*
  509.  * ----------------------------------------------------------------------------
  510.  *
  511.  * Proc_UnsetEnvironStub --
  512.  *
  513.  *    Remove the given environment variable from the current process's 
  514.  *    environment.
  515.  *
  516.  * Results:
  517.  *    Return PROC_NOT_SET_ENVIRON_VAR if the variable is not set and
  518.  *    SYS_ARG_NOACCESS if the name is not accessible.
  519.  *
  520.  * Side effects:
  521.  *    The enviroment of the current process is modified.
  522.  *
  523.  * ----------------------------------------------------------------------------
  524.  */
  525.  
  526. ENTRY ReturnStatus
  527. Proc_UnsetEnvironStub(environVar)
  528.     Proc_EnvironVar    environVar;    /* Variable to remove. */
  529. {
  530.     register    ProcEnvironVar    *varPtr;
  531.     register    Proc_ControlBlock    *procPtr;
  532.     char                *namePtr;
  533.     int                    nameLength;
  534.     int                    nameAccLength;
  535.     ReturnStatus            status;
  536.  
  537.     LOCK_MONITOR;
  538.  
  539.     procPtr = Proc_GetEffectiveProc();
  540.  
  541.     /*
  542.      * Make variable name accessible.
  543.      */
  544.  
  545.     namePtr = environVar.name;
  546.     status = Proc_MakeStringAccessible(PROC_MAX_ENVIRON_NAME_LENGTH,
  547.                        &namePtr, &nameAccLength, 
  548.                        &nameLength);
  549.     if (status != SUCCESS) {
  550.     UNLOCK_MONITOR;
  551.     return(status);
  552.     }
  553.  
  554.     /*
  555.      * Find the variable in the environment.
  556.      */
  557.  
  558.     varPtr = FindVar(procPtr->environPtr, namePtr);
  559.     Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  560.  
  561.     if (varPtr == (ProcEnvironVar *) NIL) {
  562.     UNLOCK_MONITOR;
  563.     return(PROC_NOT_SET_ENVIRON_VAR);
  564.     }
  565.  
  566.     /*
  567.      * Unset the variable by freeing up the space that was allocated
  568.      * for it.
  569.      */
  570.  
  571.     free((Address) varPtr->name);
  572.     varPtr->name = (char *) NIL;
  573.     free((Address) varPtr->value);
  574.     varPtr->value = (char *) NIL;
  575.  
  576.     UNLOCK_MONITOR;
  577.  
  578.     return(SUCCESS);
  579. }
  580.  
  581.  
  582. /*
  583.  * ----------------------------------------------------------------------------
  584.  *
  585.  * Proc_GetEnvironVarStub --
  586.  *
  587.  *    Return the value of the given environment variable in the current 
  588.  *    process's environment.
  589.  *
  590.  * Results:
  591.  *    SYS_ARG_NOACCESS if place to store value is a bad address or 
  592.  *    PROC_NOT_SET_ENVIRON_VAR if the environment variable doesn't 
  593.  *    exist.
  594.  *
  595.  * Side effects:
  596.  *    None.
  597.  *
  598.  * ----------------------------------------------------------------------------
  599.  */
  600.  
  601. ReturnStatus
  602. Proc_GetEnvironVarStub(environVar)
  603.     Proc_EnvironVar    environVar;    /* Variable to retrieve. */
  604. {
  605.     register    ProcEnvironVar    *varPtr;
  606.     register    Proc_ControlBlock    *procPtr;
  607.     char                *namePtr;
  608.     int                    nameLength;
  609.     int                    nameAccLength;
  610.     ReturnStatus            status;
  611.  
  612.     LOCK_MONITOR;
  613.  
  614.     procPtr = Proc_GetEffectiveProc();
  615.  
  616.     /*
  617.      * Make name accessible.
  618.      */
  619.  
  620.     namePtr = environVar.name;
  621.     status = Proc_MakeStringAccessible(PROC_MAX_ENVIRON_NAME_LENGTH,
  622.                        &namePtr, &nameAccLength, &nameLength);
  623.     if (status != SUCCESS) {
  624.     UNLOCK_MONITOR;
  625.     return(status);
  626.     }
  627.  
  628.     /*
  629.      * Find the variable.  If not found then return an error.
  630.      */
  631.  
  632.     varPtr = FindVar(procPtr->environPtr, namePtr);
  633.     Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  634.  
  635.     if (varPtr == (ProcEnvironVar *) NIL) {
  636.     UNLOCK_MONITOR;
  637.     return(PROC_NOT_SET_ENVIRON_VAR);
  638.     }
  639.  
  640.     /*
  641.      * Copy out the value of the variable.
  642.      */
  643.  
  644.     if (Proc_ByteCopy(FALSE, varPtr->valueLength + 1, (Address) varPtr->value, 
  645.             (Address) environVar.value) != SUCCESS) {
  646.     UNLOCK_MONITOR;
  647.     return(SYS_ARG_NOACCESS);
  648.     }
  649.  
  650.     UNLOCK_MONITOR;
  651.     return(SUCCESS);
  652. }
  653.  
  654.  
  655. /*
  656.  * ----------------------------------------------------------------------------
  657.  *
  658.  * Proc_GetEnvironRangeStub --
  659.  *
  660.  *    Return as many environment variables as possible in the given range.  
  661.  *    Variables are numbered from 0.  The actual number of environment 
  662.  *    variables returned is returned in numActualVarsPtr.  The null 
  663.  *    string is returned for any environment variables that are not set.
  664.  *
  665.  * Results:
  666.  *    Error status if some error occcurs.  SUCCESS otherwise.
  667.  *
  668.  * Side effects:
  669.  *    None.
  670.  *
  671.  * ----------------------------------------------------------------------------
  672.  */
  673.  
  674. ENTRY ReturnStatus
  675. Proc_GetEnvironRangeStub(first, last, envArray, numActualVarsPtr)
  676.     int                first;            /* First var to 
  677.                              * retrieve. */
  678.     int                last;            /* Last var to 
  679.                              * retrieve. */
  680.     register    Proc_EnvironVar    *envArray;        /* Where to 
  681.                              * store vars.*/
  682.     int                *numActualVarsPtr;    /* Number of vars
  683.                              * retrieved. */
  684. {
  685.     Proc_EnvironVar            *saveEnvPtr;
  686.     register    ProcEnvironVar    *varPtr;
  687.     register    Proc_ControlBlock    *procPtr;
  688.     ReturnStatus            status = SUCCESS;
  689.     int                    i;
  690.     int                    numBytes;
  691.     int                    numVars;
  692.     char                nullChar = '\0';
  693.  
  694.     LOCK_MONITOR;
  695.  
  696.     if (last < first || first < 0) {
  697.     UNLOCK_MONITOR;
  698.     return(SYS_INVALID_ARG);
  699.     }
  700.  
  701.     procPtr = Proc_GetEffectiveProc();
  702.  
  703.     if (first >= procPtr->environPtr->size) {
  704.     numVars = 0;
  705.     status = Vm_CopyOut(sizeof(numVars), 
  706.             (Address) &numVars, (Address) numActualVarsPtr);
  707.     if (status != SUCCESS) {
  708.         status = SYS_ARG_NOACCESS;
  709.     }
  710.     UNLOCK_MONITOR;
  711.     return(status);
  712.     }
  713.     if (last >= procPtr->environPtr->size) {
  714.     last = procPtr->environPtr->size - 1;
  715.     }
  716.  
  717.     /*
  718.      * Make the environment array accessible.
  719.      */
  720.  
  721.     i = (last - first + 1) * sizeof(Proc_EnvironVar);
  722.     Vm_MakeAccessible(VM_READONLY_ACCESS, i,
  723.         (Address) envArray, &numBytes, (Address *) &saveEnvPtr);
  724.     envArray = saveEnvPtr;
  725.     if (numBytes != i) {
  726.     if (envArray != (Proc_EnvironVar *) NIL) {
  727.         Vm_MakeUnaccessible((Address) envArray, numBytes);
  728.     }
  729.     UNLOCK_MONITOR;
  730.     return(SYS_ARG_NOACCESS);
  731.     }
  732.  
  733.     /*
  734.      * Copy out the environment variables.
  735.      */
  736.     for (i = first, varPtr = &(procPtr->environPtr->varArray[first]);
  737.      i <= last;
  738.      i++, varPtr++, envArray++) {
  739.  
  740.     if (varPtr->name == (char *) NIL) {
  741.         if (Vm_CopyOut(1, (Address) &nullChar, 
  742.                (Address) envArray->name) != SUCCESS) {
  743.         status = SYS_ARG_NOACCESS;
  744.         break;
  745.         } else {
  746.         continue;
  747.         }
  748.     }
  749.  
  750.     if (Vm_CopyOut(varPtr->nameLength + 1, (Address) varPtr->name, 
  751.         (Address) envArray->name) != SUCCESS) {
  752.         status = SYS_ARG_NOACCESS;
  753.         break;
  754.     }
  755.  
  756.     if (Vm_CopyOut(varPtr->valueLength + 1, (Address) varPtr->value, 
  757.         (Address) envArray->value) != SUCCESS) {
  758.         status = SYS_ARG_NOACCESS;
  759.         break;
  760.     }
  761.     }
  762.  
  763.     Vm_MakeUnaccessible((Address) saveEnvPtr, numBytes);
  764.  
  765.     if (status == SUCCESS) {
  766.     numVars = last - first + 1;
  767.     if (Vm_CopyOut(sizeof(numVars), (Address) &numVars, 
  768.                (Address) numActualVarsPtr) != SUCCESS) {
  769.         status = SYS_ARG_NOACCESS;
  770.     }
  771.     }
  772.  
  773.     UNLOCK_MONITOR;
  774.     return(status);
  775. }
  776.  
  777.  
  778. /*
  779.  * ----------------------------------------------------------------------------
  780.  *
  781.  * Proc_CopyEnvironStub --
  782.  *
  783.  *    Give the current process its own copy of the environment.
  784.  *
  785.  * Results:
  786.  *    Always returns SUCCESS.
  787.  *
  788.  * Side effects:
  789.  *    New environment allocated.
  790.  *
  791.  * ----------------------------------------------------------------------------
  792.  */
  793.  
  794. ENTRY ReturnStatus
  795. Proc_CopyEnvironStub()
  796. {
  797.     register    Proc_EnvironInfo    *newEnvironPtr;
  798.     register    Proc_ControlBlock    *procPtr;
  799.  
  800.     LOCK_MONITOR;
  801.  
  802.     procPtr = Proc_GetEffectiveProc();
  803.  
  804.     if (procPtr->environPtr->refCount == 1) {
  805.     UNLOCK_MONITOR;
  806.     return(SUCCESS);
  807.     }
  808.  
  809.     newEnvironPtr = (Proc_EnvironInfo *) malloc(sizeof(Proc_EnvironInfo));
  810.     newEnvironPtr->refCount = 1;
  811.     newEnvironPtr->size = procPtr->environPtr->size;
  812.     newEnvironPtr->varArray = (ProcEnvironVar *) 
  813.         malloc(sizeof(ProcEnvironVar) * newEnvironPtr->size);
  814.  
  815.     DoCopyEnviron(newEnvironPtr->size, procPtr->environPtr->varArray, 
  816.           newEnvironPtr->size, newEnvironPtr->varArray);
  817.  
  818.     DecEnvironRefCount(procPtr->environPtr);
  819.     procPtr->environPtr = newEnvironPtr;
  820.  
  821.     UNLOCK_MONITOR;
  822.  
  823.     return(SUCCESS);
  824. }
  825.  
  826. /*
  827.  * ----------------------------------------------------------------------------
  828.  *
  829.  * Proc_InstallEnvironStub --
  830.  *
  831.  *    Install the given environment as the environment of the current
  832.  *    process.
  833.  *
  834.  * Results:
  835.  *    Error if args invalid or inaccessible.  SUCCESS otherwise.
  836.  *
  837.  * Side effects:
  838.  *    A new enviroment is allocated.
  839.  *
  840.  * ----------------------------------------------------------------------------
  841.  */
  842.  
  843. ENTRY ReturnStatus
  844. Proc_InstallEnvironStub(environ, numVars)
  845.     Proc_EnvironVar    environ[];    /* Environment to install. */
  846.     int            numVars;    /* Number of variables in the
  847.                      * environment. */
  848. {
  849.     register    Proc_EnvironVar        *userEnvironPtr;
  850.     register    Proc_EnvironInfo    *newEnvironPtr;
  851.     register    ProcEnvironVar    *varPtr;
  852.     Proc_EnvironVar            *saveEnvironPtr;
  853.     int                    environLength;
  854.     int                    i;
  855.     int                    nameAccLength;
  856.     int                    nameLength;
  857.     char                *namePtr;
  858.     int                    valueAccLength;
  859.     int                    valueLength;
  860.     char                *valuePtr;
  861.     ReturnStatus            status;
  862.     Proc_ControlBlock            *procPtr;    
  863.  
  864.     LOCK_MONITOR;
  865.  
  866.     if (numVars > PROC_MAX_ENVIRON_SIZE) {
  867.     UNLOCK_MONITOR;
  868.     return(SYS_INVALID_ARG);
  869.     }
  870.  
  871.     /*
  872.      * Make the users environment array accessible.
  873.      */
  874.     userEnvironPtr = (Proc_EnvironVar *) NIL;
  875.     if (numVars > 0) {
  876.     Vm_MakeAccessible(VM_READONLY_ACCESS, numVars * sizeof(Proc_EnvironVar),
  877.                   (Address) environ, &environLength, 
  878.               (Address *) &saveEnvironPtr);
  879.     userEnvironPtr = saveEnvironPtr;
  880.     if (environLength != numVars * sizeof(Proc_EnvironVar)) {
  881.         if (userEnvironPtr != (Proc_EnvironVar *) NIL) {
  882.         Vm_MakeUnaccessible((Address) userEnvironPtr, environLength);
  883.         }
  884.         UNLOCK_MONITOR;
  885.         return(SYS_ARG_NOACCESS);
  886.     }
  887.     }
  888.  
  889.     /*
  890.      * Allocate a new environment of size at least MIN_ENVIRON_SIZE.
  891.      */
  892.  
  893.     newEnvironPtr = (Proc_EnvironInfo *) malloc(sizeof(Proc_EnvironInfo));
  894.     newEnvironPtr->refCount = 1;
  895.     if (numVars < MIN_ENVIRON_SIZE) {
  896.     newEnvironPtr->size = MIN_ENVIRON_SIZE;
  897.     } else {
  898.     newEnvironPtr->size = numVars;
  899.     }
  900.     newEnvironPtr->varArray = (ProcEnvironVar *) 
  901.         malloc(sizeof(ProcEnvironVar) * newEnvironPtr->size);
  902.  
  903.     /*
  904.      * Read in the users environment variables and store them in the
  905.      * new environment.
  906.      */
  907.  
  908.     for (i = 0, varPtr = newEnvironPtr->varArray; 
  909.      i < numVars;
  910.      userEnvironPtr++, varPtr++, i++) {
  911.     if (userEnvironPtr->name != (char *) USER_NIL) {
  912.         namePtr = userEnvironPtr->name;
  913.         status = Proc_MakeStringAccessible(PROC_MAX_ENVIRON_NAME_LENGTH,
  914.                        &namePtr, &nameAccLength, &nameLength);
  915.         if (status != SUCCESS) {
  916.         Vm_MakeUnaccessible((Address) saveEnvironPtr, environLength);
  917.         FreeEnviron(newEnvironPtr, i - 1, TRUE);
  918.         UNLOCK_MONITOR;
  919.         return(SYS_ARG_NOACCESS);
  920.         }
  921.         valuePtr = userEnvironPtr->value;
  922.         status = Proc_MakeStringAccessible(PROC_MAX_ENVIRON_VALUE_LENGTH,
  923.                    &valuePtr, &valueAccLength, &valueLength);
  924.         if (status != SUCCESS) {
  925.         Vm_MakeUnaccessible((Address) saveEnvironPtr, environLength);
  926.         Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  927.         FreeEnviron(newEnvironPtr, i - 1, TRUE);
  928.         UNLOCK_MONITOR;
  929.         return(SYS_ARG_NOACCESS);
  930.         }
  931.  
  932.         varPtr->name = (char *) malloc(nameLength + 1);
  933.         varPtr->nameLength = nameLength;
  934.         bcopy(namePtr, varPtr->name, nameLength + 1);
  935.  
  936.         varPtr->value = (char *) malloc(valueLength + 1);
  937.         varPtr->valueLength = valueLength;
  938.         bcopy(valuePtr, varPtr->value, valueLength + 1);
  939.  
  940.         Proc_MakeUnaccessible((Address) namePtr, nameAccLength);
  941.         Proc_MakeUnaccessible((Address) valuePtr, valueAccLength);
  942.     } else {
  943.         varPtr->name = (char *) NIL;
  944.         varPtr->value = (char *) NIL;
  945.     }
  946.     }
  947.  
  948.     if (numVars > 0) {
  949.     Vm_MakeUnaccessible((Address) saveEnvironPtr, environLength);
  950.     }
  951.  
  952.     /*
  953.      * If we allocated more than the user requested then set the excess
  954.      * variables to NIL.
  955.      */
  956.  
  957.     for (; i < newEnvironPtr->size; i++, varPtr++) {
  958.     varPtr->name = (char *) NIL;
  959.     varPtr->value = (char *) NIL;
  960.     }
  961.  
  962.     /*
  963.      * Make this new environment the environment of the current process.
  964.      */
  965.  
  966.     procPtr = Proc_GetEffectiveProc();
  967.     DecEnvironRefCount(procPtr->environPtr);
  968.     procPtr->environPtr = newEnvironPtr;
  969.  
  970.     UNLOCK_MONITOR;
  971.     return(SUCCESS);
  972. }
  973.